package com.xiaoyu.lib_av.proxy

import `in`.srain.cube.request.JsonData
import `in`.srain.cube.util.CLog
import `in`.srain.cube.util.Env
import com.xiaoyu.lib_av.datamodel.CallMessage
import com.xiaoyu.lib_av.datamodel.CallVendorType
import com.xiaoyu.lib_av.manager.AgoraManager
import com.xiaoyu.lib_av.manager.CallManager
import com.xiaoyu.base.app.GlobalUI
import `in`.srain.cube.concurrent.AppThreads
import `in`.srain.cube.util.log.LogClient
import `in`.srain.cube.util.log.LogClientManagerProxy
import `in`.srain.cube.util.log.LogEvent
import com.xiaoyu.lib_av.log.AVLogClient
import io.agora.rtc.Constants.AUDIO_RECORDING_QUALITY_HIGH
import io.agora.rtc.IRtcEngineEventHandler
import io.agora.rtc.RtcEngine
import io.agora.rtm.*
import java.io.File

abstract class AgoraAbstractProxy : IAVProxy {

    protected val rtmClient = AgoraManager.getInstance().rtmClient
    protected val callingIdSet = AgoraManager.getInstance().callingIdSet

    protected var mRtcEngine: RtcEngine? = null

    override val vendorType: String
        @CallVendorType.CallVendorTypeDef
        get() = AgoraManager.getInstance().vendorType

    override val logDir: File
        get() = AgoraManager.getInstance().logDir

    override var isEnableSpeaker: Boolean
        get() = mRtcEngine?.isSpeakerphoneEnabled == true
        set(enable) {
            mRtcEngine?.setEnableSpeakerphone(enable)
        }

    override val lastCallRecordFilePath: String
        get() = CallManager.instance.callRecordCacheDir.path.toString() + File.separator + AgoraManager.getInstance().lastRecordFileName

    override val isCalling: Boolean
        get() = AgoraManager.getInstance().isCalling

    open val rtmClientListener = object : RtmClientListener {
        override fun onPeersOnlineStatusChanged(p0: MutableMap<String, Int>?) {
        }

        override fun onMediaUploadingProgress(p0: RtmMediaOperationProgress?, p1: Long) {
        }

        override fun onImageMessageReceivedFromPeer(p0: RtmImageMessage?, p1: String?) {
        }

        override fun onConnectionStateChanged(state: Int, reason: Int) {
            CLog.d(TAG, "Connection state changes to %s, reason: %s", state, reason)
            if (state == RtmStatusCode.ConnectionState.CONNECTION_STATE_ABORTED) {
                val logEvent = LogEvent("connectionStateChanged")
                logEvent.putData("state", state)
                logEvent.putData("reason", reason)
                AVLogClient.instance.addLog(logEvent)

                GlobalUI.getInstance().showToastForLong("多设备登录会造成语音电话相关功能异常，请重新登录")
            }
        }

        override fun onMessageReceived(rtmMessage: RtmMessage, s: String) {
            val message = CallMessage.from(JsonData.create(rtmMessage.text))
            val logEvent = LogEvent("onMessageReceived")
            logEvent.putData("message", message)
            AVLogClient.instance.addLog(logEvent)

            CallManager.instance.onMessageReceive(message)
        }

        override fun onFileMessageReceivedFromPeer(p0: RtmFileMessage?, p1: String?) {
        }

        override fun onMediaDownloadingProgress(p0: RtmMediaOperationProgress?, p1: Long) {
        }

        override fun onTokenExpired() {
            CLog.d(TAG, "onTokenExpired()")
            val logEvent = LogEvent("tokenExpired")
            AVLogClient.instance.addLog(logEvent)
            CallManager.instance.onTokenExpired()
        }
    }

    open val rtcEngineEventHandler = object : IRtcEngineEventHandler() {}

    fun onCreate(channelProfile: Int) {
        mRtcEngine = AgoraManager.getInstance().tryCreateRtcEngine(channelProfile)
    }

    override fun setMute(mute: Boolean): Boolean {
        val success = mRtcEngine?.muteLocalAudioStream(mute) == 0
        if (success) {
            CallManager.instance.onLocalAudioMuteStatusChanged(mute)
        }

        val logEvent = LogEvent("mute")
        logEvent.putData("mute", mute)
        logEvent.putData("success", success)
        AVLogClient.instance.addLog(logEvent)
        return success
    }

    protected fun tryStartRecording() {
        val isDirExits = ensureOrMakeCallCacheDir()
        if (!isDirExits) {
            return
        }
        val file = File(lastCallRecordFilePath)
        if (file.exists()) {
            startRecording(file)
        } else {
            try {
                if (file.createNewFile()) {
                    startRecording(file)
                }
            } catch (e: Throwable) {
                e.printStackTrace()
            }
        }
    }

    private fun startRecording(file: File) {
        mRtcEngine?.startAudioRecording(file.path, SAMPLE_RATE, AUDIO_RECORDING_QUALITY_HIGH)
    }

    private fun ensureOrMakeCallCacheDir(): Boolean {
        val dirFile = File(CallManager.instance.callRecordCacheDir.path.path)
        return dirFile.exists() || dirFile.mkdir()
    }

    override fun stopRecording() {
        mRtcEngine?.stopAudioRecording()
    }

    override fun enableLocalVideo(enable: Boolean) : Boolean{
        val success = mRtcEngine?.enableLocalVideo(enable) == 0
        if (success) {
            CallManager.instance.onLocateVideoDisableStateChanged(!enable)
        }

        val logEvent = LogEvent("enableLocalVideo")
        logEvent.putData("enable", enable)
        logEvent.putData("success", success)
        AVLogClient.instance.addLog(logEvent)

        return success
    }

    override fun switchCamera() {
        mRtcEngine?.switchCamera()
    }

    protected fun tryToastInDevMode(toast: CharSequence) {
        if (Env.isDevOrInDevMode()) {
            AppThreads.runOnMainThread {
                GlobalUI.getInstance().showToast(toast)
            }
        }
    }

    companion object {
        const val TAG = "lib-av"
        const val RTC_RESULT_OK = 0

        private const val SAMPLE_RATE = 48
    }
}
